﻿using Infrastructure.Helper;
using Infrastructure.Model;
using Infrastructure.Util;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System.Security.Claims;
using System.Text;
using System.Text.RegularExpressions;
using UAParser;

namespace Infrastructure.Extensions
{
    /// <summary>
    /// / HttpContext扩展类，提供了一些常用的HttpContext相关的扩展方法
    /// </summary>
    public static class HttpContextExtension
    {
        // 根据用户信息获取Claims信息
        public static List<Claim> GetClaims(this HttpContext context, LoginUser user)
        {
            List<Claim> list = new List<Claim>
        {
            new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid", user.UserId.ToString()),
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", user.UserName),
            new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata", JsonConvert.SerializeObject(user))
        };
            if (user.GroupIds != null)
            {
                list.Add(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", string.Join(",", user.GroupIds)));
            }
            if (user.Permissions != null)
            {
                list.Add(new Claim("perm", string.Join(",", user.Permissions)));
            }
            return list;
        }

        // 获取客户端信息
        public static ClientInfo GetClientInfo(this HttpContext context)
        {
            string userAgent = context.GetUserAgent();
            Parser @default = Parser.GetDefault((ParserOptions)null);
            return @default.Parse(userAgent);
        }

        // 获取客户端IP地址
        public static string GetClientUserIp(this HttpContext context)
        {
            if (context == null)
            {
                return "";
            }
            string text = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(text))
            {
                text = context.Connection.RemoteIpAddress.ToString();
            }
            if (string.IsNullOrEmpty(text) || text.Contains("::1"))
            {
                text = "127.0.0.1";
            }
            text = text.Replace("::ffff:", "127.0.0.1");
            return IsIP(text) ? text : "127.0.0.1";
        }

        // 获取用户信息
        public static LoginUser GetCurrentUserInfo(this HttpContext context)
        {
            LoginUser loginUser = JwtUtil.GetLoginUser(context,
                (IDistributedCache)App.ServiceProvider.GetService(typeof(IDistributedCache)));
            if (loginUser != null && loginUser?.UserId != "")
            {
                return loginUser;
            }
            return null;
        }

        // 获取个性化样式信息
        public static string GetCustomStyle(string key)
        {
            // 获取分布式缓存服务
            IDistributedCache cache = (IDistributedCache)App.ServiceProvider.GetService(typeof(IDistributedCache));
            DistributedCacheManager distributedCacheManager = new DistributedCacheManager(cache);

            // 获取缓存中指定键的个性化样式信息，并返回
            bool isExisted = true;
            return distributedCacheManager.Get<string>("Personalized:" + key, out isExisted);
        }

        // 获取用户名
        public static string GetName(this HttpContext context)
        {
            return context.User?.Identity?.Name;
        }

        // 获取请求的Url
        public static string GetRequestUrl(this HttpContext context)
        {
            return (context != null) ? context.Request.Path.Value : "";
        }

        // 获取Token
        public static string GetToken(this HttpContext context, IDistributedCache distributedCache)
        {
            string text = context.ReadHeader("auth_token");
            if (string.IsNullOrEmpty(text))
            {
                string text2 = context.ReadHeader("Authorization");
                if (string.IsNullOrWhiteSpace(text2))
                {
                    text2 = context.ReadCookie("SessionId");
                }
                text = distributedCache.GetString("LoginSession:" + text2);
            }
            return text;
        }

        // 获取用户的ID
        public static long GetUId(this HttpContext context)
        {
            string value = context.User.FindFirst("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid").Value;
            return (!string.IsNullOrEmpty(value)) ? long.Parse(value) : 0;
        }

        // 获取User-Agent信息
        public static string GetUserAgent(this HttpContext context)
        {
            StringValues stringValues = context.Request.Headers["User-Agent"];
            return stringValues;
        }

        // 获取用户地点信息
        public static string[] GetUserLocation(this HttpContext context)
        {
            LoginUser loginUser = JwtUtil.GetLoginUser(context,
                (IDistributedCache)App.ServiceProvider.GetService(typeof(IDistributedCache)));
            if (loginUser != null && loginUser?.UserId != "")
            {
                return loginUser.Locations?.ToArray() ?? Array.Empty<string>();
            }
            return Array.Empty<string>();
        }

        // 判断当前请求是否为Ajax请求
        public static bool IsAjaxRequest(this HttpRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            return request.Headers["X-Requested-With"] == "XMLHttpRequest" ||
                   (request.Headers != null && request.Headers["X-Requested-With"] == "XMLHttpRequest");
        }

        // 判断给定的字符串是否为一个有效的IP地址
        public static bool IsIP(string ip)
        {
            return Regex.IsMatch(ip, "^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");
        }

        // 移除登录用户的会话 ID
        public static void RemoveLoginUserSessionId(string userId)
        {
            // 获取分布式缓存服务
            IDistributedCache cache = (IDistributedCache)App.ServiceProvider.GetService(typeof(IDistributedCache));
            DistributedCacheManager distributedCacheManager = new DistributedCacheManager(cache);
            // 检查缓存中是否存在该用户的会话 ID 列表
            bool isExisted = true;
            List<string> sessionIds = distributedCacheManager.Get<List<string>>("LoginUserSessionId:" + userId, out isExisted);
            // 如果列表不存在，则直接返回
            if (!isExisted)
            {
                return;
            }
            // 遍历列表中的会话 ID，并从缓存中移除相关的登录会话数据
            foreach (string sessionId in sessionIds)
            {
                distributedCacheManager.Remove("LoginSession:" + sessionId);
            }
            // 最后移除存储登录用户会话 ID 列表的缓存键
            distributedCacheManager.Remove("LoginUserSessionId:" + userId);
        }

        // 保存认证信息到 HttpContext
        public static List<Claim> SaveAuth(this HttpContext context, string userId, string sessionId)
        {
            // 创建包含用户信息的声明列表
            List<Claim> claims = new List<Claim>
        {
                // Microsoft Windows 中唯一标识用户或实体的声明 (claim)，即主要安全标识符（Primary SID）。
                // 在身份验证和授权过程中，这个声明通常用于标识用户或实体的主要安全标识符，这在 Windows 系统中是一个重要的标识符。
            new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid", userId),
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid", sessionId)
        };

            // 创建身份对象
            ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, "Cookies");

            // 使用异步方式进行登录
            Task.Run(async () =>
            {
                await context.SignInAsync("Cookies", new ClaimsPrincipal(claimsIdentity), new AuthenticationProperties
                {
                    IsPersistent = true,
                    AllowRefresh = true,
                    ExpiresUtc = DateTimeOffset.Now.AddDays(1.0)
                });
            }).Wait(); // 等待异步操作完成

            return claims; // 返回声明列表
        }

        // 设置个性化样式信息
        public static void SetCustomStyle(string key, string value)
        {
            // 获取分布式缓存服务
            IDistributedCache cache = (IDistributedCache)App.ServiceProvider.GetService(typeof(IDistributedCache));
            DistributedCacheManager distributedCacheManager = new DistributedCacheManager(cache);

            // 将指定键的个性化样式信息存入缓存，设置过期时间为两年
            distributedCacheManager.Set("Personalized:" + key, value, new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTime.Now.AddYears(2)
            });
        }

        // 设置登录用户的会话 ID
        public static void SetLoginUserSessionId(string userId, string sessionId)
        {
            // 获取分布式缓存服务
            IDistributedCache cache = (IDistributedCache)App.ServiceProvider.GetService(typeof(IDistributedCache));
            DistributedCacheManager distributedCacheManager = new DistributedCacheManager(cache);

            // 检查缓存中是否存在该用户的会话 ID 列表
            bool isExisted = true;
            List<string> sessionIds = distributedCacheManager.Get<List<string>>("LoginUserSessionId:" + userId, out isExisted);
            // 如果列表为空，则创建新列表并添加会话 ID
            if (sessionIds == null)
            {
                sessionIds = new List<string>();
                sessionIds.Add(sessionId);
            }
            else if (!sessionIds.Contains(sessionId)) // 如果列表中不包含当前会话 ID，则添加
            {
                sessionIds.Add(sessionId);
            }

            // 如果缓存中已存在该键，则先移除旧值
            if (isExisted)
            {
                distributedCacheManager.Remove("LoginUserSessionId:" + userId);
            }

            // 将更新后的会话 ID 列表存入缓存，设置过期时间为一年
            distributedCacheManager.Set("LoginUserSessionId:" + userId, sessionIds, new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTime.Now.AddYears(1)
            });
        }
    }
}
